package com.wiz.data.factory;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.BitSet;
import java.util.Iterator;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.primitives.Bytes;
import com.wiz.data.util.HexUtil;
import com.wiz.data.vo.to.DataMessageTemplate;
import com.wiz.data.vo.to.MabDataTO;
import com.wiz.data.vo.to.MessageFiled;

public class MessageDataFactory {
	private static MessageDataFactory instance;
	private static Object obj = new Object();
	
	/**
	 * CBC向量对象
	 */
	private static AlgorithmParameterSpec iv = null;

	/**
	 * CBC向量
	 */
	private static final byte[] DESIV = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00 };

	/**
	 * 补齐数据
	 */
	private static final byte[] PADDING_DATA = { 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00 };

	static {
		iv = new IvParameterSpec(DESIV);
	}
	
	private MessageDataFactory(){}
	
	public static MessageDataFactory getInstance() {
		if (instance != null) {
			return instance;
		}
		synchronized (obj) {
			if (instance != null) {
				return instance;
			}
			instance = new MessageDataFactory();
		}
		return instance;
	}
	
	/**
	 * 返回发送mab数据byte数组
	 * @param mabDataTO 消息数据封装实体
	 * @param messageTemplate 初始化消息模板
	 * @return
	 * @throws CloneNotSupportedException 
	 */
	public byte[] getMabMessage(MabDataTO mabDataTO, DataMessageTemplate messageTemplate) throws CloneNotSupportedException{
		DataMessageTemplate message = (DataMessageTemplate) messageTemplate.clone();
		LinkedHashMultimap<Integer, MessageFiled> map = message.getMessageFiledMap();
		Iterator iter = map.values().iterator();
		byte[] nbs = new byte[0];
		while(iter.hasNext()){
//		      Map.Entry<Integer, MessageFiled> entry = (Map.Entry<Integer, MessageFiled>)iter.next();
			  MessageFiled filed = (MessageFiled) iter.next();
		      filed.setValue(mabDataTO.getValueByIndex(filed.getIndex()));
		      nbs = Bytes.concat(nbs,filed.toBytes());
		      System.out.println("index="+filed.getIndex()+"    now="+HexUtil.Bytes2HexString(nbs));
		}
		return nbs;
	}
	
	/**
	 * 获取指定内容的mac
	 * @param mab 加密数据
	 * @param key 加密key
	 * @return
	 * @throws Exception
	 */
	public byte[] getMac(byte[] mab, byte[] key) throws Exception {
		byte[] paddedBuf = paddingData(mab);// 补位
		byte[] data = new byte[8];// 前8位
		System.arraycopy(paddedBuf, 0, data, 0, 8);
		for (int i = 8; i < paddedBuf.length; i += 8) {// 每8位异或
			byte[] tmp = new byte[8];
			System.arraycopy(paddedBuf, i, tmp, 0, 8);
			data = xorblock(data, tmp);
		}
//		SecretKey deskey = new SecretKeySpec(key, "DES");
//		// 单倍加密
//		Cipher c1 = Cipher.getInstance("DES" + "/ECB/NoPadding");
//		c1.init(Cipher.ENCRYPT_MODE, deskey);
//		return c1.doFinal(data);
		byte[] rdata = new byte[8];
		System.arraycopy(desEncrypt(data,key), 0, rdata, 0, 8);
		return rdata;
	}
	
	public static void main(String[] args) throws Exception {
//		String key = "2y0k5E8y";
//		String data = "54-04-A6-A9-7F-DE";
//		System.out.println(HexUtil.Bytes2HexString(getMac(data.getBytes(),key.getBytes())));
	}
	
	private byte[] desEncrypt(byte[] plainText,byte[] desKey) throws Exception{
		SecureRandom sr = new SecureRandom();
        byte rawKeyData[] = desKey;
        DESKeySpec dks = new DESKeySpec(rawKeyData);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey key = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, key, sr);
        byte data[] = plainText;
        byte encryptedData[] = cipher.doFinal(data);
        return encryptedData;
	}
	
	/**
	 * 生成位元表byte[]
	 * @param messageTemplate 初始化消息模板
	 * @return
	 */
	public byte[] getMtiMessage(DataMessageTemplate messageTemplate){
		Multimap<Integer, MessageFiled> paramMap = messageTemplate.getMessageFiledMap();
		BitSet bs = createBitmapBitSet(paramMap);
		int count = bs.size()/4;//计算占多少位
		StringBuffer sb = new StringBuffer();
		for(int i=count;i>=1;i--){
			int value = 0;//每4位和值
			for(int j=1;j<=4;j++){
				if(bs.get((i-1)*4+j)){
					value+=(8>>(4-j));
				}
			}
			sb.append(Integer.toHexString(value));
		}
		return sb.toString().getBytes();
	}
	
	/**
	 * 解析mab数据
	 * @param mab
	 * @param mti
	 * @return 返回消息解析数据的封装实体
	 * @throws UnsupportedEncodingException
	 */
	public MabDataTO getMabDataTO(byte[] mab,byte[] mti) throws UnsupportedEncodingException{
		MabDataTO mabTO = new MabDataTO();
		BitSet bitSet = getWeiYuan(mti);
		int addLength = 0;//累加长度
		if(bitSet.get(1)){//1域
			mabTO.setWiz_1_dataType(getString(mab,addLength,2));
			addLength+=2;
		}
		if(bitSet.get(2)){//2域
			mabTO.setWiz_2_time(getLong(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(3)){//3域
			mabTO.setWiz_3_endTime(getLong(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(10)){//10域 
			mabTO.setWiz_10_hqId(getInteger(mab,addLength));
			addLength+=4;
		}
		if(bitSet.get(11)){//11域
			mabTO.setWiz_11_stationId(getInteger(mab,addLength));
			addLength+=4;
		}
		if(bitSet.get(12)){//12域
			mabTO.setWiz_12_fdId(getLong(mab,addLength));;
			addLength+=8;
		}
		if(bitSet.get(13)){//13域
			mabTO.setWiz_13_memberId(getLong(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(14)){//14域
			mabTO.setWiz_14_authorityId(getString(mab,addLength,19));
			addLength+=19;
		}
		if(bitSet.get(17)){//17域
			mabTO.setWiz_17_prId(getLong(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(20)){//20域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_20_hqName(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(21)){//21域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_21_stationName(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(23)){//23域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_23_memberName(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(27)){//27域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_27_prName(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(39)){//39域 
			mabTO.setWiz_39_type(getString(mab,addLength,1));
			addLength+=1;
		}
		if(bitSet.get(40)){//40域
			mabTO.setWiz_40_receivableAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(41)){//41域
			mabTO.setWiz_41_realincomeAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(42)){//42域
			mabTO.setWiz_42_discountAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(43)){//43域
			mabTO.setWiz_43_intergalAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(44)){//44域
			mabTO.setWiz_44_amountPoint(getInteger(mab, addLength));
			addLength+=4;
		}
		if(bitSet.get(45)){//45域
			mabTO.setWiz_45_price(getDouble(mab, addLength));
			addLength+=8;
		}
		if(bitSet.get(46)){//46域
			mabTO.setWiz_46_priceOther(getDouble(mab, addLength));
			addLength+=8;
		}
		if(bitSet.get(47)){//47域
			mabTO.setWiz_47_saleAmount(getDouble(mab, addLength));
			addLength+=8;
		}
		if(bitSet.get(48)){//48域
			mabTO.setWiz_48_memberFrozenAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(49)){//49域
			mabTO.setWiz_49_memberBalanceAmount(getDouble(mab,addLength));
			addLength+=8;
		}
		if(bitSet.get(50)){//50域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_50_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(51)){//51域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_51_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(52)){//52域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_52_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(53)){//50域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_53_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(54)){//54域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_54_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(55)){//55域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_55_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(56)){//56域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_56_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(57)){//57域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_57_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(58)){//58域  长度1
			mabTO.setWiz_58_spareString(getString(mab,addLength,1));
			addLength+=1;
		}
		if(bitSet.get(59)){//59域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_59_spareLString(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(60)){//60域  长度1
			mabTO.setWiz_60_status(getString(mab,addLength,1));
			addLength+=1;
		}
		if(bitSet.get(62)){//62域 
			int length = getInteger(mab, addLength);
			addLength+=4;
			mabTO.setWiz_62_message(getString(mab,addLength,length));
			addLength+=length;
		}
		if(bitSet.get(63)){//63域 2字节
			mabTO.setWiz_63_responseCode(getString(mab,addLength,2));
			addLength+=2;
		}
		if(bitSet.get(64)){//64域 8字节
			mabTO.setWiz_64_dynakey(getString(mab,addLength,8));
			addLength+=8;
		}
		return mabTO;
	}
	
	/**
	 * 根据截取区间获取字符
	 * @param bs
	 * @param start
	 * @param length
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String getString(byte[] bs,int start,int length) throws UnsupportedEncodingException{
		byte[] nbs = new byte[length];
		for(int i=0;i<length;i++){
			nbs[i] = bs[start+i];
		}
		return new String(nbs,"UTF-8");
	}
	
	/**
	 * 转换int
	 * @param bs
	 * @param start
	 * @return
	 */
	private int getInteger(byte[] bs, int start) {
		int number = bs[0+start] & 0xFF;
		// "|="按位或赋值。
		number |= ((bs[1+start] << 8) & 0xFF00);
		number |= ((bs[2+start] << 16) & 0xFF0000);
		number |= ((bs[3+start] << 24) & 0xFF000000);
		return number;
	}
	
	/**
	 * 转换long
	 * @param bs
	 * @param start
	 * @return
	 */
	private long getLong(byte[] bs,int start){
		long s = 0; 
        long s0 = bs[0+start] & 0xff;// 最低位 
        long s1 = bs[1+start] & 0xff; 
        long s2 = bs[2+start] & 0xff; 
        long s3 = bs[3+start] & 0xff; 
        long s4 = bs[4+start] & 0xff;// 最低位 
        long s5 = bs[5+start] & 0xff; 
        long s6 = bs[6+start] & 0xff; 
        long s7 = bs[7+start] & 0xff; 
        // s0不变 
        s1 <<= 8; 
        s2 <<= 16; 
        s3 <<= 24; 
        s4 <<= 8 * 4; 
        s5 <<= 8 * 5; 
        s6 <<= 8 * 6; 
        s7 <<= 8 * 7; 
        s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7; 
		return s;
	}
	
	/**
	 * 转换double
	 * @param bs
	 * @param start
	 * @return
	 */
	private double getDouble(byte[] bs,int start){
		long s = (((long) (bs[0+start] & 0xff) << 56) 
				| ((long) (bs[1+start] & 0xff) << 48) | ((long) (bs[2+start] & 0xff) << 40)
                | ((long) (bs[3+start] & 0xff) << 32) | ((long) (bs[4+start] & 0xff) << 24)
                | ((long) (bs[5+start] & 0xff) << 16) | ((long) (bs[6+start] & 0xff) << 8) 
                | ((long) (bs[7+start] & 0xff)));
		return Double.longBitsToDouble(s);
	}

	/**
	 * 获取位元表中的参数域信息
	 * @param wy
	 * @return
	 */
	private BitSet getWeiYuan(byte[] mti){
		BitSet bs = new BitSet(64);
		int l = mti.length;
		for(int i=0;i<l;i++){
			int r = Integer.parseInt(new String(new byte[]{mti[l-1-i]}),16);
			for(int j=1;j<=4;j++){
				int comp = 1<<(j-1);
				if((r & comp) == comp){
					bs.set(i*4+j);
				}
			}
		}
		return bs;
	}
	
	
	/**
	 * 不足8位，右补0补齐数据
	 * @param src
	 * @return
	 */
	private byte[] paddingData(byte[] src) {
		int len = src.length;
		if(len == 0){
			return new byte[]{0,0,0,0,0,0,0,0};
		}
		if ((len % 8) > 0) {
			int padLen = 8 - len % 8;
			int paddedLen = padLen + len;
			byte[] ret = new byte[paddedLen];
			System.arraycopy(src, 0, ret, 0, len);
			System.arraycopy(PADDING_DATA, 0, ret, len, padLen);
			return ret;
		}
		return src;
	}

	/**
	 * 异或
	 * @param d1
	 * @param d2
	 * @return
	 */
	private final byte[] xorblock(byte[] d1, byte[] d2) {
		byte[] d = new byte[d1.length];
		for (short i = (short) 0; i < (short) d1.length; i++) {
			d[i] = (byte) (d1[i] ^ d2[i]);
		}
		return d;
	}
	
	/**
	 * 根据参数域创建位元表
	 * @param paramMap
	 * @return
	 */
	private BitSet createBitmapBitSet(Multimap<Integer, MessageFiled> paramMap) {
		BitSet bs = new BitSet(64);
		for (int i = 1; i < 65; i++) {
			if (paramMap.containsKey(i)) {
				bs.set(i);
			}
		}
//		if (bs.length() > 64) {
//			// Extend to 128 if needed
//			BitSet b2 = new BitSet(128);
//			b2.or(bs);
//			bs = b2;
//			bs.set(0);
//		}
		return bs;
	}
}
